package ExecuteEngine;

import java.util.ArrayList;
import java.util.List;

import parse.IntegerItem;
import parse.VarcharItem;

import Const.Constant;
import Const.RC;
import RecordManagement.*;
import SystemManagement.*;

public class Delete_operation extends Operation {
	public Operation op;
	public RID rid;
	public SM_Manager sm;
	Tuple t;
	List<String> other_attr_list = new ArrayList<String>();
	List<String> my_attr = new ArrayList<String>();
	List<String> other_rel = new ArrayList<String>();
	int offsets[];
	
	public Delete_operation(Operation op, SM_Manager sm){
		this.op = op;
		this.sm = sm;
		this.type = Operation.DELETE;
	}
	
	public void Close() {
		op.Close();
	}

	public Tuple GetNext() {
		rid = ((TableScan)(((Select)op).op)).rid;
		RM_FileHandle fileHandle = ((TableScan)(((Select)op).op)).fileHandle;
		fileHandle.DeleteRec(rid);
		
		return null;
	}

	public RC.rc Open() {
	   	List<DataAttrInfo> info = new ArrayList<DataAttrInfo>();
    	String tableName = ((TableScan)(((Select)op).op)).tableName;
    	sm.GetDataAttrInfo(tableName, info);
    	
    	DataAttrInfo_foreignkeycat foreignkeyData = new DataAttrInfo_foreignkeycat();
    	StringBuffer s = new StringBuffer(tableName);
    	s.setLength(Constant.MAXNAME);
    	
    	ScanType st = new ScanType(foreignkeyData.foreignkeycat[2].attrType,
    			foreignkeyData.foreignkeycat[2].attrLength,
    			foreignkeyData.foreignkeycat[2].offset, 
			    ScanType.OP_EQ, s.toString().getBytes(), 
                ScanType.PIN_NORMAL);

    	RM_FileScan fileScan = new RM_FileScan(sm.foreignkeycatHandle, st);
    	other_attr_list = new ArrayList<String>(); /* other relation */
    	my_attr = new ArrayList<String>(); 
    	other_rel = new ArrayList<String>();
    	RM_Record record;
    	
    	while((record = fileScan.GetNextRec()) != null){
    		byte data[] = record.data;
    		byte part[] = new byte[foreignkeyData.foreignkeycat[1].attrLength];
    		System.arraycopy(data, foreignkeyData.foreignkeycat[1].offset, part, 0, foreignkeyData.foreignkeycat[1].attrLength);
    		other_attr_list.add(new String(part));
    		
    		part = new byte[foreignkeyData.foreignkeycat[0].attrLength];
    		System.arraycopy(data, foreignkeyData.foreignkeycat[0].offset, part, 0, foreignkeyData.foreignkeycat[0].attrLength);
    		other_rel.add(new String(part));
    		
    		part = new byte[foreignkeyData.foreignkeycat[3].attrLength];
    		System.arraycopy(data, foreignkeyData.foreignkeycat[3].offset, part, 0, foreignkeyData.foreignkeycat[3].attrLength);
    		my_attr.add(new String(part));
    	}
    	fileScan.CloseScan();
    	
    	offsets = new int[other_attr_list.size()];
    	for(int i=0; i<other_attr_list.size(); i++){
    		s = new StringBuffer(my_attr.get(i));
    		s.setLength(Constant.MAXNAME);
    		
    		for(int j=0; j<info.size(); j++){
    			if(info.get(j).attrName.equals(s.toString())){
    				offsets[i] = j;
    				break;
    			}
    		}
    	}
    	
    	return op.Open();
	}

	public boolean hasNext() {
		while(op.hasNext()){
			t = op.GetNext();

	    	/* Check the foreign key */	
	    	List<DataAttrInfo> info = new ArrayList<DataAttrInfo>();
        	
	    	int i=0;
	    	for(i=0; i<other_attr_list.size(); i++){
	    		String r = other_rel.get(i);
	    		String rel = new String();
	    		for(int k=0; k<r.length(); k++){
	    			if(r.charAt(k)!=0){
	    				char c[] = new char[1];
	    				c[0] = r.charAt(k);
	    				rel+=(new String(c));
	    			}
	    			else
	    				break;
	    		}
	    			
	        	sm.GetDataAttrInfo(rel, info);
	        	int other_offset = 0;
	        	for(int k=0; k<info.size(); k++){
	        		if(info.get(k).attrName.equals(other_attr_list.get(i))){
	        			other_offset = k;
	        			break;
	        		}
	        	}
	        	
	        	RM_FileHandle handle = null;
		    	try{
		    		handle = sm.rm.OpenFile(rel+".db");
		    	}
		    	catch(java.io.IOException e){
		    		
		    	}
		    	
				ScanType st = new ScanType(ScanType.TYPE_STRING, 
		                   Constant.MAXNAME, 0, ScanType.OP_NO,
		                   null, ScanType.PIN_NORMAL);
		
		    	RM_FileScan fileScan = new RM_FileScan(handle, st);
		    	RM_Record record;
		    	
		    	boolean mark = false;
		    	while((record = fileScan.GetNextRec()) != null){
		    		byte data[] = new byte[info.get(other_offset).attrLength];
		    		System.arraycopy(record.data, info.get(other_offset).offset, data, 0, info.get(other_offset).attrLength);
		    		
		    		if(info.get(i).attrType == ScanType.TYPE_INT){
						int n = 0;
						
						for(int j=0; j<4; j++){
							if(data[j] < 0)
								n += 256*(4-j);
						}
						
						n += (((int)data[0]) << 24) + (((int)data[1]) << 16) + (((int)data[2]) << 8) + data[3];
						
						if(n == ((IntegerItem)(t.tuple.get(offsets[i]).value)).value){
							mark = true;
							break;
						}
		    		}
		    		else
		    		{
		    			String temp = new String(data);
		    			String temp2 = ((VarcharItem)(t.tuple.get(offsets[i]).value)).value.toString();
		    			if(temp.length() > temp2.length()){
		    				StringBuffer s = new StringBuffer(temp2);
		    				s.setLength(temp.length());
		    				temp2 = s.toString();
		    			}
		    			else{
		    				StringBuffer s = new StringBuffer(temp);
		    				s.setLength(temp2.length());
		    				temp = s.toString();
		    			}
		    			
		    			if(temp.equals(((VarcharItem)(t.tuple.get(offsets[i]).value)).value.toString())){
		    				mark = true;
		    				break;
		    			}
		    		}
		    	}
		    	
		    	if(mark == true){
		    		System.out.println("Error: foreign key constraint");
		    		break;
		    	}
	    	}
	    	
	    	if(i == other_attr_list.size())
	    		return true;
		}
		
		return false;
	}
	
	public List<String> GetTitles(){
		return null;
	}
}
